// Copyright (C) Kumo inc. and its affiliates.
// Author: Jeff.li lijippy@163.com
// All rights reserved.
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as published
// by the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program.  If not, see <https://www.gnu.org/licenses/>.
//


#pragma once

#include <atomic>
#include <cstddef>
#include <cstdint>
#include <vector>

inline size_t count_trailing_zeros(uint64_t x) {
    return x == 0 ? 64 : __builtin_ctzll(x);
}

inline size_t count_leading_zeros(uint64_t x) {
    return x == 0 ? 64 : __builtin_clzll(x);
}

namespace kumo::pollux {
#if defined(__GNUC__) || defined(__clang__)
#define INLINE_LAMBDA __attribute__((__always_inline__))
#else
#define INLINE_LAMBDA
#endif

#if defined(__has_feature)
#if __has_feature(thread_sanitizer)
#define TSAN_BUILD 1
#endif
#endif

    /// Define tsan_atomic<T> to be std::atomic<T?> for tsan builds and
    /// T otherwise. This allows declaring variables like statistics
    /// counters that do not have to be exact nor have synchronized
    /// semantics. This deals with san errors while not incurring the
    /// bus lock overhead at run time in regular builds.
#ifdef TSAN_BUILD
template <typename T>
using tsan_atomic = std::atomic<T>;

template <typename T>
inline T tsanAtomicValue(const std::atomic<T>& x) {
  return x;
}

/// Lock guard in tsan build and no-op otherwise.
template <typename T>
using tsan_lock_guard = std::lock_guard<T>;

#else

    template<typename T>
    using tsan_atomic = T;

    template<typename T>
    inline T tsanAtomicValue(T x) {
        return x;
    }

    template<typename T>
    struct TsanEmptyLockGuard {
        TsanEmptyLockGuard(T & /*ignore*/) {
        }
    };

    template<typename T>
    using tsan_lock_guard = TsanEmptyLockGuard<T>;

#endif

    template<typename T>
    inline void resizeTsanAtomic(
        std::vector<tsan_atomic<T> > &vector,
        int32_t newSize) {
        std::vector<tsan_atomic<T> > newVector(newSize);
        auto numCopy = std::min<int32_t>(newSize, vector.size());
        for (auto i = 0; i < numCopy; ++i) {
            newVector[i] = tsanAtomicValue(vector[i]);
        }
        vector = std::move(newVector);
    }
} // namespace kumo::pollux
